/************************************
 * Package: RGcpp					*
 * Authors: Rui Eduardo Gouveia Gil	*
 * Date: 2010						*
 ************************************/
#include "rgcpp/sys/JobScheduler.h"
#include "rgcpp/sys/Job.h"

namespace rgcpp
{

Job::Job() : status(JS_WAITING), jobScheduler(NULL), jobId(0), doneExc(false)
{
	this->updateExecuteTime(0);
}

Job::Job(unsigned int offset) : status(JS_WAITING), jobScheduler(NULL), jobId(0), doneExc(false)
{
	this->updateExecuteTime(offset);
}

Job::~Job()
{

}

void Job::updateExecuteTime(unsigned int offset)
{
	time(&this->execTime);
	this->execTime += offset;
}

unsigned int Job::getJobId()
{
	return this->jobId;
}

time_t Job::getExecuteTime()
{
	return this->execTime;
}

boost::shared_ptr<Job> Job::getParent()
{
	return this->parent;
}

JobScheduler* Job::getJobScheduler()
{
	return this->jobScheduler;
}

JobStatus Job::getStatus() const
{
	return status;
}

void Job::setStatus(JobStatus status)
{
	this->status = status;
}

bool Job::wait(unsigned int timeout)
{
	if(this->status != JS_WAITING && this->status != JS_EXECUTING)
		return true;

	boost::mutex::scoped_lock lock(doneMut);

	time_t timeTimeout;

	time(&timeTimeout);
	timeTimeout += timeout;

	boost::xtime xt;
	xt.nsec = 0;
	xt.sec = timeTimeout;

	return doneCond.timed_wait(lock,xt);
}

void Job::scheduleChildJob(boost::shared_ptr<Job> child)
{
	this->jobScheduler->scheduleChildJob(this->jobId,child);
}

void Job::setJobId(unsigned int jobId)
{
	this->jobId = jobId;
}

void Job::setParent(boost::shared_ptr<Job> parent)
{
	this->parent = parent;
}

void Job::setJobScheduler(JobScheduler* jobScheduler)
{
	this->jobScheduler = jobScheduler;
}

void Job::executeJob()
{
	this->status = JS_EXECUTING;
	this->execute();
	this->doneExc = true;
}

void Job::notifyParent(JobStatus status)
{
	this->status = status;
	this->final();
	this->doneCond.notify_all();

	if(this->parent)
		this->parent->childFinish(this->jobId);
}

void Job::addChild(boost::shared_ptr<Job> child)
{
	boost::recursive_mutex::scoped_lock lock(mut);
	this->childs[child->getJobId()] = child;
}

bool Job::pendingJobs()
{
	boost::recursive_mutex::scoped_lock lock(mut);
	return !this->childs.empty();
}

void Job::childFinish(const unsigned int childJobId)
{
	boost::recursive_mutex::scoped_lock lock(mut);
	if(this->childs.find(childJobId) == this->childs.end())
	{
		Throw(NoSuchElementException("Child job not found..."));
	}

	boost::shared_ptr<Job> child = this->childs[childJobId];
	this->childs.erase(childJobId);

	this->callBack(child);

	if(this->childs.size() == 0 && this->doneExc)
	{
		this->final();
		this->doneCond.notify_all();
	}
}

}
